home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / machack / Hacks95 / Closure.sit / Closure / Sources / GX Graphics Libraries / layout library.c < prev    next >
Text File  |  1995-06-24  |  16KB  |  510 lines

  1. /* layout library.c -- Line Layout library routines.
  2.     
  3. CHANGE LOG
  4.  
  5. Date      Person      Action
  6. ----      ------      ------
  7.  
  8. 900517    ERM       • Created.
  9. 900702    ERM       • Converted to new graphics-like interface.
  10. 900703    ERM       • Add LineOptions parameter to SingleLayout guys.
  11. 900712    DGO       • Fixed NewEasyLayout, which wasn't correctly doing LineOptions.
  12. 900731    DGO       • Changed "line" to "lineOpts" throughout.
  13.                     • Added code to initialize controls in SetLayoutStyle if passed-in
  14.                       parameter "layoutControls" is nil.
  15. 900803    ERM       • Removed controls initialization from NewSingleLayout.
  16.                     • Various other formatting clean-up.
  17. 900826    DGO       • Added first cut at the paragraph functions.
  18. 900828    DGO       • Fixed sense-of-sign bug. *BLUSH*
  19. 900912    ERM       • Bagged references to hard-coded layout feature levels.
  20. 900914    ERM       • Added GetStyleLayoutFeatureNames.
  21. 900917    ERM       • THINK C 3.0 compatability changes.
  22. 910114    DGO       • Removed overhangRect references.
  23. 910410    DGO       • Merged Mike's changes to font manager.
  24.                     • Added lineHeight parameter to NewParagraph.
  25. 910415    ERM + DGO • Added include of ToolUtils.
  26. 910516    OWS       • Converted to ANSI-style function declarations.
  27.                     • Updated includes for Think C 5.0.
  28. 910529    DGO       • Changed to final 1.0 form.
  29. 910626    DGO       • Bug fixing in NewParagraph (undisposed shape, bad pointer).
  30. 910820    DGO       • Added NewDiscontiguousSelection function.
  31.                     • Minor name changes.
  32. 911118    ERM       • Replaced GetStyleRunFeatureNames w/ GetStyleRunFeatureTypeNames, GetStyleRunFeatureSelectorNames.
  33. 911120    ERM       • Removed gxRunFeatureType from RunFeatureSelectorName.
  34. 911124    DGO       • Moved NewDiscontiguousSelection to selection library.
  35. 920309    ERM       • GXNewLayout now has explicit run counts.
  36. 920505    DGO       • Fixed NewStyledParagraph linebreaking bug.
  37. 930623        DGO                •    Added GXIgnoreGraphicsNotice for text_attributes_already_set.
  38.  
  39. */
  40.  
  41. /* Copyright ©1990-1993 Apple Computer, Inc.  All rights reserved. */
  42.  
  43. #ifndef powerc
  44.  #pragma pointers_in_D0                            
  45. #endif
  46.  
  47. #include <Types.h>
  48. #include <Memory.h>
  49. #include <Resources.h>
  50. #include <ToolUtils.h>
  51.  
  52. #include "graphics toolbox.h"
  53. #include "graphics routines.h"
  54. #include "math routines.h"
  55. #include "layout types.h"
  56. #include "layout routines.h"
  57. #include "font routines.h"
  58.  
  59. #ifndef powerc
  60.  #pragma pointers_in_A0                    
  61. #endif
  62.  
  63. #include "layout library.h"
  64. #include "font library.h"
  65.  
  66. void InitializeLayoutOptions (gxLayoutOptions *layoutOptions)
  67. { layoutOptions->width = 0;
  68.   layoutOptions->flush = 0;
  69.   layoutOptions->just = 0;
  70.   layoutOptions->flags = 0;
  71.   layoutOptions->baselineRec = nil;
  72. }
  73.  
  74. void SetDefaultPriorityJustOverride (gxPriorityJustificationOverride *override)
  75. { short i;
  76.   gxWidthDeltaRecord  *pDelta;
  77.  
  78.   pDelta = override->deltas;
  79.   for (i = 0; i < gxNumberOfJustificationPriorities; i++)
  80.   { pDelta->growFlags = pDelta->shrinkFlags = 0;
  81.     pDelta->beforeGrowLimit = pDelta->afterGrowLimit = 
  82.       pDelta->beforeShrinkLimit = pDelta->afterShrinkLimit = 0;
  83.     pDelta++;
  84.   } /* endloop i */
  85. }
  86.  
  87. void InitializeRunControls (gxRunControls *runControls)
  88. { runControls->flags = 0;
  89.   runControls->beforeWithStreamShift = runControls->afterWithStreamShift = 0;
  90.   runControls->crossStreamShift = 0;
  91.   runControls->imposedWidth = 0;
  92.   runControls->track = 0;
  93.   runControls->hangingInhibitFactor = runControls->kerningInhibitFactor = 0;
  94.   runControls->baselineType = gxRomanBaseline;
  95.   runControls->decompositionAdjustmentFactor = 0;
  96. }
  97.  
  98. void InitializeStyleRunOverrides (StyleRunOverrides *overrides)
  99. { overrides->priorityJustOverride = nil;
  100.   overrides->glyphJustOverrides = nil;
  101.   overrides->glyphJustOverridesCount = 0;
  102.   overrides->glyphSubstitutions = nil;
  103.   overrides->glyphSubstitutionsCount = 0;
  104.   overrides->kerningAdjustments = nil;
  105.   overrides->kerningAdjustmentsCount = 0;
  106. }
  107.  
  108. static void SetStyleNamedFont(gxStyle s, unsigned char* name)
  109. {
  110.   // gxFont fontID = FindPNameFont(gxFullFontName, name);
  111.   gxFont fontID = FindPNameFont(gxFamilyFontName, name);
  112.   if (fontID != GXGetStyleFont(s))
  113.     GXSetStyleFont(s, fontID);
  114. }
  115.  
  116. void SetLayoutStyle (
  117.   gxStyle             s,
  118.   long txFont, long txFace,
  119.   Fixed             textSize,
  120.   gxTextAttribute     attr,
  121.   gxRunControls       *runControls,
  122.   gxRunFeature        runFeatures[],
  123.   long              runFeaturesCount,
  124.   StyleRunOverrides *overrides)
  125. { gxRunControls localControls;
  126.  
  127. #ifdef debugging  
  128.   GXIgnoreGraphicsNotice(attributes_already_set);
  129.   GXIgnoreGraphicsNotice(text_attributes_already_set);
  130. #endif
  131.  
  132.   (void)GXConvertQDFont(s, txFont, txFace);
  133.   //SetStyleNamedFont (s, (unsigned char*)gxFontName);
  134.   GXSetStyleTextSize (s, textSize);
  135.   GXSetStyleTextAttributes (s, attr);
  136.  
  137.   if (!runControls)
  138.   { InitializeRunControls(&localControls);
  139.     runControls = &localControls;
  140.   }
  141.   
  142.   GXSetStyleRunControls (s, runControls);
  143.  
  144.   if (runFeatures) GXSetStyleRunFeatures (s, runFeaturesCount, runFeatures);
  145.  
  146.   if (overrides)
  147.   { if (overrides->glyphSubstitutions)
  148.       GXSetStyleRunGlyphSubstitutions (s, overrides->glyphSubstitutionsCount, overrides->glyphSubstitutions);
  149.     if (overrides->kerningAdjustments)
  150.       GXSetStyleRunKerningAdjustments (s, overrides->kerningAdjustmentsCount, overrides->kerningAdjustments);
  151.     if (overrides->glyphJustOverrides)
  152.       GXSetStyleRunGlyphJustOverrides (s, overrides->glyphJustOverridesCount, overrides->glyphJustOverrides);
  153.     if (overrides->priorityJustOverride)
  154.       GXSetStyleRunPriorityJustOverride (s, overrides->priorityJustOverride);
  155.   }
  156. #ifdef debugging  
  157.   GXPopGraphicsNotice();
  158.   GXPopGraphicsNotice();
  159. #endif
  160. }
  161.  
  162. gxStyle NewLayoutStyle (
  163.     long txFont, long txFace,
  164.   Fixed             textSize,
  165.   gxTextAttribute     attr,
  166.   gxRunControls       *runControls,
  167.   gxRunFeature        runFeatures[],
  168.   long              runFeaturesCount,
  169.   StyleRunOverrides *overrides)
  170. { gxStyle newStyle = GXNewStyle ();
  171.  
  172.   SetLayoutStyle (
  173.     newStyle,
  174.     txFont, txFace,
  175.     textSize,
  176.     attr,
  177.     runControls,
  178.     runFeatures,
  179.     runFeaturesCount,
  180.     overrides);
  181.   
  182.   return (newStyle);
  183. }
  184.  
  185. #if 0
  186. gxShape NewSingleLayout (
  187.   char              *text,
  188.   char              *gxFontName,
  189.   Fixed             textSize,
  190.   gxLayoutOptions     *options,
  191.   gxPoint             *position,
  192.   gxTextAttribute     attr,
  193.   gxRunControls       *runControls,
  194.   gxRunFeature        runFeatures[],
  195.   long              runFeaturesCount,
  196.   StyleRunOverrides *overrides)
  197. { gxStyle newLayoutStyle;
  198.   gxShape newLayoutShape;
  199.   short len, level = 0;
  200.   char  *s;
  201.   
  202.   newLayoutStyle = NewLayoutStyle (
  203.     gxFontName,
  204.     textSize,
  205.     attr,
  206.     runControls,
  207.     runFeatures,
  208.     runFeaturesCount,
  209.     overrides);
  210.  
  211.   for (len = 0, s = text; *s++ != 0; len++) ;
  212.   
  213.   newLayoutShape = GXNewLayout (
  214.     1,
  215.     &len,
  216.     (const void **) &text,
  217.     1,
  218.     &len,
  219.     &newLayoutStyle,
  220.     1,
  221.     &len,
  222.     &level,
  223.     options,
  224.     position);
  225.   
  226.   GXDisposeStyle (newLayoutStyle);
  227.   
  228.   return newLayoutShape;
  229. }
  230. #endif
  231.  
  232. /* NewParagraph is the simplest of the paragraph creation functions. It assumes a single
  233.     gxStyle for the whole paragraph, and does its own deduction about where the paragraph
  234.     ends (namely at a hard stop, CR or HT). */
  235.  
  236. short CountBytes(char *text);
  237. short CountBytes(char *text)
  238.   {
  239.   short count = 0;
  240.   while (*text != 13 && *text != 9)
  241.     {text++; count++;}
  242.   return count;
  243.   } /* CountBytes */
  244.  
  245. ParagraphRecordHandle NewParagraph(
  246.   char    *text,
  247.   gxStyle   baseStyle,
  248.   Fixed   width,
  249.   long    justified,
  250.   Fixed   lineHeight,
  251.   gxPoint   *firstOrigin)
  252.   {
  253.   /* Constants */
  254.   #define extraLineGap ff(2)
  255.   #define lineStartsCount 50
  256.   /* Variables */
  257.   boolean               startIsStaked;
  258.   gxByteOffset            lineStarts[lineStartsCount], newLineStart, nextStake,
  259.                         nls2, priorStake, thisLineStart;
  260.   char                  *pChar;
  261.   Fixed                 currLineDelta, textSize;
  262.   gxLayoutOptions         options;
  263.   ParagraphRecordHandle paraHandle;
  264.   gxShape                 bigLayout, thisLine;
  265.   short                 byteCount, i, level = 0, nextLineIndex;
  266.   
  267.   byteCount = CountBytes(text); /* doesn't count the CR or HT!! */
  268.   bigLayout = GXNewLayout(
  269.     1,
  270.     &byteCount,
  271.     (const void **) &text,
  272.     1,
  273.     &byteCount,
  274.     &baseStyle,
  275.     1,
  276.     &byteCount,
  277.     &level,
  278.     nil,
  279.     firstOrigin);
  280.   
  281.   /* We next compute the gxLine breaks and store the offsets that correspond to them in a
  282.       temporary array. */
  283.   
  284.   thisLineStart = 0;
  285.   nextLineIndex = 0;
  286.   while (thisLineStart < byteCount && nextLineIndex < lineStartsCount - 1)
  287.     {
  288.     lineStarts[nextLineIndex++] = thisLineStart;
  289.     newLineStart = GXGetLayoutBreakOffset(
  290.       bigLayout, thisLineStart, width, 0, nil, &startIsStaked, &priorStake, &nextStake);
  291.     if (newLineStart == byteCount) break;
  292.     /* Now backtrack to first prior space. */
  293.     nls2 = newLineStart;
  294.     pChar = text + newLineStart - 1;
  295.     while (nls2 >= 0 && *pChar != ' ')
  296.       {
  297.       pChar--;
  298.       nls2--;
  299.       }
  300.     if (nls2 < 0) thisLineStart = newLineStart;
  301.     else thisLineStart = nls2;
  302.     }
  303.   lineStarts[nextLineIndex] = byteCount;
  304.   
  305.   /* Allocate space for the ParagraphRecord. */
  306.   
  307.   paraHandle = (ParagraphRecordHandle) NewHandle(
  308.     (Size) (sizeof(ParagraphRecord) + nextLineIndex * sizeof(gxShape)));
  309.   (*paraHandle)->nLayouts = nextLineIndex;
  310.   
  311.   /* Now create the layouts and place them in the ParagraphRecord. */
  312.   
  313.   InitializeLayoutOptions(&options);
  314.   options.width = width;
  315.   if (justified) options.just = fract1;
  316.   textSize = GXGetStyleTextSize(baseStyle);
  317.   currLineDelta = 0;
  318.   
  319.   for (i = 0; i < nextLineIndex; i++)
  320.     {
  321.     if (i == nextLineIndex - 1) options.just = 0; /* don't justify the last gxLine... */
  322.     thisLine = GXNewLayoutFromRange(
  323.       bigLayout, lineStarts[i], lineStarts[i+1], &options, nil);
  324.     if (currLineDelta) GXMoveShape(thisLine, 0, currLineDelta);
  325.     (*paraHandle)->layouts[i] = thisLine;
  326.     currLineDelta += (lineHeight ? lineHeight : (textSize + extraLineGap));
  327.     }
  328.   
  329.   (*paraHandle)->totalHeight = currLineDelta;
  330.   
  331.   GXDisposeShape(bigLayout);
  332.   return paraHandle;
  333.   } /* NewParagraph */
  334.  
  335. static char *GetTextPiecePtr(
  336.   const void    *text[],
  337.   const short   textRunLengths[],
  338.   short         offset)
  339.   
  340.   {
  341.   char  **pPiece = (char **) text;
  342.   short oCopy = offset;
  343.   short *runLength = (short *) textRunLengths;
  344.   while (oCopy > *runLength)
  345.     {oCopy -= *runLength++; pPiece++;}
  346.   return *pPiece + oCopy;
  347.   } /* GetTextPiecePtr */
  348.  
  349. static long GetPreviousOffset(gxShape layout, long offset)
  350. { unsigned short firstGlyph, secondGlyph;
  351.   gxLayoutOffsetState offsetState;
  352.   static long offsetStateSizes[] = {1, 1, 2, 2, 0};
  353.   
  354.   GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
  355.   
  356.   return offset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
  357. }
  358.  
  359. static long GetNextOffset(gxShape layout, long offset)
  360. { unsigned short firstGlyph, secondGlyph;
  361.   gxLayoutOffsetState offsetState;
  362.   static long offsetStateSizes[] = {1, 2, 1, 2, 0};
  363.   
  364.   GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
  365.   
  366.   return offset + offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
  367. }
  368.  
  369. ParagraphRecordHandle NewStyledParagraph(
  370.   long                textRunCount,
  371.   const void          *text[],
  372.   const short         textRunLengths[],
  373.   long                styleRunCount,
  374.   const gxStyle         styles[],
  375.   const short         styleRunLengths[],
  376.   long                levelRunCount,
  377.   const short         levels[],
  378.   const short         levelRunLengths[],
  379.   long                totalByteCount,
  380.   const gxLayoutOptions *layoutOptions,
  381.   Fixed               lineHeight,
  382.   const gxPoint         *firstOrigin)
  383.   {
  384.   /* Variables */
  385.   boolean               startIsStaked;
  386.   gxByteOffset            lineStarts[lineStartsCount], newLineStart, nextStake,
  387.                         nls2, priorStake, thisLineStart;
  388.   char                  *pChar, *pSav;
  389.   Fixed                 currLineDelta, lineAscent, lineDescent;
  390.   gxLayoutOptions         specialOptions;
  391.   ParagraphRecordHandle paraHandle;
  392.   gxShape                 bigLayout, thisLine;
  393.   short                 i, level = 0, nextLineIndex;
  394.   
  395.   specialOptions = *layoutOptions;
  396.   specialOptions.just = specialOptions.flush = 0;
  397.   specialOptions.width = 0;
  398.   
  399.   bigLayout = GXNewLayout(
  400.     textRunCount,
  401.     textRunLengths,
  402.     text,
  403.     styleRunCount,
  404.     styleRunLengths,
  405.     styles,
  406.     levelRunCount,
  407.     levelRunLengths,
  408.     levels,
  409.     &specialOptions,
  410.     firstOrigin);
  411.   
  412.   /* We next compute the gxLine breaks and store the offsets that correspond to them in a
  413.       temporary array. */
  414.   
  415.   thisLineStart = 0;
  416.   nextLineIndex = 0;
  417.   while (thisLineStart < totalByteCount && nextLineIndex < lineStartsCount - 1)
  418.     {
  419.     lineStarts[nextLineIndex++] = thisLineStart;
  420.     newLineStart = GXGetLayoutBreakOffset(
  421.       bigLayout,
  422.       thisLineStart,
  423.       layoutOptions->width,
  424.       0,
  425.       nil,
  426.       &startIsStaked,
  427.       &priorStake,
  428.       &nextStake);
  429.     if (newLineStart == totalByteCount) break;
  430.     /* Now backtrack to first prior space. */
  431.     nls2 = newLineStart;
  432.     pSav = pChar = GetTextPiecePtr(text, textRunLengths, GetPreviousOffset(bigLayout, newLineStart));
  433.     while (nls2 >= lineStarts[nextLineIndex-1] && *pChar != ' ')
  434.       pChar = GetTextPiecePtr(text, textRunLengths, nls2 = GetPreviousOffset(bigLayout, nls2));
  435.  
  436.     if (nls2 <= lineStarts[nextLineIndex-1]) thisLineStart = newLineStart;
  437.     else
  438.       {
  439.       if (pSav != pChar) nls2 = GetNextOffset(bigLayout, nls2);
  440.       thisLineStart = nls2;
  441.       }
  442.     }
  443.   lineStarts[nextLineIndex] = (short) totalByteCount;
  444.   
  445.   /* Allocate space for the ParagraphRecord. */
  446.   
  447.   paraHandle = (ParagraphRecordHandle) NewHandle(
  448.     (Size) (sizeof(ParagraphRecord) + nextLineIndex * sizeof(gxShape)));
  449.   (*paraHandle)->nLayouts = nextLineIndex;
  450.   
  451.   /* Now create the layouts and place them in the ParagraphRecord. */
  452.   
  453.   specialOptions = *layoutOptions;
  454.   currLineDelta = 0;
  455.   
  456.   for (i = 0; i < nextLineIndex; i++)
  457.     {
  458.     if (i == nextLineIndex - 1) specialOptions.just = 0;  /* don't justify last gxLine... */
  459.     thisLine = GXNewLayoutFromRange(
  460.       bigLayout, lineStarts[i], lineStarts[i+1], &specialOptions, nil);
  461.     if (currLineDelta) GXMoveShape(thisLine, 0, currLineDelta);
  462.     (*paraHandle)->layouts[i] = thisLine;
  463.     if (lineHeight) currLineDelta += lineHeight;
  464.     else
  465.       {
  466.       GXGetLayoutSpan(thisLine, &lineAscent, &lineDescent);
  467.       currLineDelta += lineAscent + lineDescent + extraLineGap;
  468.       }
  469.     }
  470.   
  471.   (*paraHandle)->totalHeight = currLineDelta;
  472.   
  473.   GXDisposeShape(bigLayout);
  474.   return paraHandle;
  475.   } /* NewStyledParagraph */
  476.  
  477. /* DisposeParagraph disposes of the memory associated with a paragraph. While currently
  478.     simple, it could be more involved if the paragraph itself retains more information. */
  479.  
  480. void DisposeParagraph(ParagraphRecordHandle paraRec)
  481.   {
  482.   short i;
  483.   for (i = 0; i < (*paraRec)->nLayouts; i++)
  484.     GXDisposeShape((*paraRec)->layouts[i]);
  485.   DisposeHandle((Handle) paraRec);
  486.   } /* DisposeParagraph */
  487.  
  488. /* GetLayoutBounds returns a gxShape corresponding to the bounds of the specified layout. It
  489.     differs from GXGetShapeBounds in two respects: first, it returns a gxShape (rather than just
  490.     a gxRectangle); and second, it takes both the layout's position and its gxMapping into account
  491.     (GXGetShapeBounds only takes the layout's position into account). */
  492.  
  493. gxShape GetLayoutBounds(gxShape layout)
  494.   {
  495.   gxMapping   thisMapping;
  496.   gxRectangle thisRect;
  497.   gxShape     rectShape;
  498.   
  499.   GXGetShapeBounds(layout, 0, &thisRect);
  500.   rectShape = GXNewRectangle(&thisRect);
  501. #if 0
  502.   GXIgnoreGraphicsNotice(transform_already_set);
  503.   GXSetShapeTransform(rectShape, GXGetShapeTransform(layout));
  504.   GXPopGraphicsNotice();
  505. #else
  506.   GXMapShape(rectShape, GXGetTransformMapping(GXGetShapeTransform(layout), &thisMapping));
  507. #endif
  508.   return rectShape;
  509.   } /* GetLayoutBounds */
  510.